package com.jin.webvideo.videoCache;

import com.jin.webvideo.entity.Cache;
import com.jin.webvideo.service.CacheService;
import com.jin.webvideo.util.base.URLUtil;
import com.jin.webvideo.util.cloneUtil.CloneUtil;
import com.jin.webvideo.util.sys.*;
import java.io.*;
import java.util.List;
import java.util.Map;

public class CacheThread implements Runnable{
    private static final String FORMAT = "%s_%d.ts";
    private static int failRange = 0;
    private String source;
    private Cache cache;
    private Map<String, String> header;
    private CacheService cacheService;

    public CacheThread(CacheService service, String source, Cache cache, Map<String,String> header){
        this.cacheService = service;
        this.source = source;
        this.header = header;
        this.cache = cache;
    }

    /**
     * 从url下载m3u8文件并解析
     * @param url
     * @return
     * @throws IOException
     */
    public M3U8File m3u8FromURL(String url) throws IOException {
        InputStream input = ClientUtil.httpGet(url, header, null);
        M3U8File file = new M3U8File(input);
        file.setSource(url);
        input.close();
        return file;
    }

    /**
     * 从url下载文件并重命名为name
     * @param url
     * @param name
     * @return
     */
    public synchronized boolean downloadFile(String url, String name) {
        try{
            File file = new File(name);
            if (!file.exists()){
                file.createNewFile();
            }
            InputStream inputStream = ClientUtil.httpGet(url, header, null);
            if (null == inputStream){
                return false;
            }
            FileOutputStream outputStream = new FileOutputStream(file);
            ClientUtil.write(inputStream, outputStream);
            inputStream.close();
            outputStream.close();
            return true;
        }
        catch (IOException exception){
            exception.printStackTrace();
        }
        return false;
    }

    /**
     * 批量设置TSFile的url
     * @param list
     * @param name
     */
    public void setPlayListName(List<TSFile> list, String name){
        int i = 0;
        for (TSFile item : list){
            item.setUrl(String.format(FORMAT, name, i));
            i ++;
        }
    }

    /**
     * 缓存m3u8文件
     * @param source
     * @param location
     * @param m3u8Name
     * @param tsName
     * @throws IOException
     */
    public void cacheM3u8(String source, String location, String m3u8Name, String tsName) throws IOException {
        M3U8File file = m3u8FromURL(source);

        List<TSFile> list = file.getMediaSegment();
        // 文件列表为空
        if (list.size() < 1){
            throw new IOException("无效的m3u8数据");
        }
        // 为媒体列表 或 仅缓存索引
        if (file.isMediaList() || allow(Cache.TYPE_ONLY_INDEX)){
            file.save(new File(location+m3u8Name), true);
            return;
        }
        M3U8File loaclFile = CloneUtil.clone(file);
        // 设置播放列表的本地路径
        setPlayListName(loaclFile.getMediaSegment(), tsName);
        // m3u8文件缓存本地
        loaclFile.save(new File(location + m3u8Name), false);
        // ts文件缓存到本地
        cacheTSFile(file.getMediaSegment(), loaclFile.getMediaSegment(), location);
    }

    /**
     * 缓存ts文件
     * @param tsFiles
     * @param saveFiles
     * @param location
     * @throws IOException
     */
    public void cacheTSFile(List<TSFile> tsFiles, List<TSFile> saveFiles, String location) throws IOException {
        int failFileCount = 0;
        for (int i = 0, l = tsFiles.size(); i < l; i ++){
            String url = tsFiles.get(i).getAbslotePath();
            // 将网络文件下载到本地
            if (!downloadFile(url, location + saveFiles.get(i).getUrl())){
                failFileCount++;
                // 如果失败次数超过设置的百分比，抛异常
                if (overMaxError(failFileCount, l)){
                    throw new IOException("cache fail, The maximum allowable range is exceeded");
                }
            }
        }
        System.out.println("cache success ts.size "+ tsFiles.size());
    }

    /**
     * 缓存mp4文件
     * @param source
     * @param location
     * @param fileName
     * @throws IOException
     */
    public void cacheMp4(String source, String location, String fileName) throws IOException {
        if (!downloadFile(source, location + fileName)){
            throw new IOException("cache mp4 fail");
        };
        System.out.println("cache mp4 success  "+ source );
    }
    @Override
    public void run() {
        String cachePath = cache.getLocation();
        String fileName = cache.getFileName();
        String url = cache.getUrl();
        File file = new File(cachePath);
        if (!file.exists()){
            file.mkdirs();
        }
        System.out.println(cachePath + "-->存在状态" + file.exists());
        try {
            if (URLUtil.isMp4(source)){
                cacheMp4(source, cachePath, fileName);
            }
            else{
                String tsName = fileName + System.currentTimeMillis();
                tsName = EncryptUtil.md5Hex(tsName);
                cacheM3u8(source, cachePath, fileName, tsName);
            }
            cacheService.canPlay(url);
        }
        catch (Exception e) {
            e.printStackTrace();
            System.out.println("[error cache]" + source + "--->" + file.getAbsoluteFile());
            cacheService.del(url);
        }
    }

    /**
     * @brief 失败次数大于允许的最大次数
     * @param failCount 失败次数
     * @param allCount 总数
     * @return
     */
    private boolean overMaxError(int failCount, int allCount){
        return allCount * failRange / 10000 < failCount;
    }

    private boolean allow(int typeDef){
        return 0 != ( this.cache.getCacheType() & typeDef );
    }
    protected static void setFailRange(int failRange){
        CacheThread.failRange = failRange;
    }
}
